
#include <d3dx9math.h>
#include "Engine.h"
#include "Entity.h"
#include "Camera.h"
#include "MeshReader.h"
#include "Texture.h"
#include "TEString.h"
#include "SubdivisionGeom.h"
#include "BillboardGeom.h"
#include "Input.h"
#include "TerrainGeom.h"
#include "Socket.h"

// Global Engine Variable
Engine engine;

//
// Constructor
//

Engine::Engine()
{
	// D3D Devices
	direct3DInterface = NULL;
	direct3DRenderer = NULL;
	fontS = NULL;
	fontL = NULL;

	// Rendering flag
	isRendering = false;
	renderWireframe = false;
	renderPoints = false;
	renderNormals = false;
	renderBBoxes = false;
	commandActive = false;
	lighting = true;
	lastTime = 0;

	// Main entity
	scene = new Entity(0, "Scene");

	// Camera
	camera = new Camera();
	terrain = 0;

	// Lights
	SetupLights();

	// Gravity
	gravity = -9.8f;
}

//
// Destructor
//

Engine::~Engine() 
{
	// Font
	SAFE_RELEASE(fontS);
	SAFE_RELEASE(fontL);

	// Buffer
	SAFE_RELEASE(boxIndexBuffer);

	// D3D Devices
	SAFE_RELEASE(direct3DRenderer);
	SAFE_RELEASE(direct3DInterface);

	// Release all textures
	tManager->Release();

	// Sockets
	if(mainServer) delete mainServer;
	if(mainClient) delete mainClient;
	CleanupSockets();
}

//
// Initialize
//

bool Engine::Initialize(HWND _window) 
{
	// save window variable
	window = &_window;

	// render state
	state = _STATE(MainMenu);

	if(!InitEngine()) return false;
	if(!InitStates()) return false;
	if(!input.Initialize(_window)) return false;
	if(!InitFonts())  return false;

	InitSockets();

	// temp stuff
	/**/Entity *e = new Entity(scene, "CrossHairs");
	BillboardGeom *geom = e->CreateBBGeom(false);
	geom->AddBillboard(0.01f);
	geom->LoadTexture(L"..\\images\\textures\\crossHairs.png", __white);

	Entity *e1 = LoadHeightMap("map1.raw");
	e1->Geom()->LoadTexture(L"..\\images\\textures\\grass.jpg");
	terrain = e1->Terrain();

	D3DXMATRIX m = Real3ToRotMatrix(Real3(-D3DX_PI/2, 0.0f, 0.0f));

	Entity *e2 = LoadEntity("monkeyman.entity", true);
	e2->Geom()->Rotate(&m);
	e2->GenerateBox();
	e2->GenerateOctree();
	//e2->Rotate(Real3(-D3DX_PI/2, 0.0f, 0.0f));
	player.SetModel(e2);

	Entity *e3 = LoadEntity("monkeyman.entity", true);
	e3->Geom()->Rotate(&m);
	e3->GenerateBox();
	e3->GenerateOctree();
	e3->SetPosition(Real3(5.0f, 0.0f, 5.0f));
	//e3->SetRotationalVelocity(Euler3(-D3DX_PI * 0.1f, 0.0f, 0.0f));
	//e3->SetLinearVelocity(Real3(0.1f, 0.0f, 0.0f));
	//e3->SetRotation(Real3(-D3DX_PI/2, -D3DX_PI/2, -D3DX_PI/2));

	/*ReadXMesh(scene, "monkey");
	ReadXMesh(scene, "monkey");

	Entity *monkey = scene->Children()[0]->Children()[0];
	monkey->SetPosition(Real3(5.0f, 5.0f, 5.0f));
	monkey->SetLinearVelocity(Real3(-0.5f, -0.5f, -0.5f));*/

	CreateServer();
	//JoinServer("70.191.191.202");

	return true;
}

//
// Initialization Methods
//

bool Engine::InitEngine() 
{
	// Try to create the interface
	if(!(direct3DInterface = Direct3DCreate9(D3D_SDK_VERSION)))
		return false;

	// Setup the struct to create the render device
	D3DPRESENT_PARAMETERS d3params; 
	ZeroMemory( &d3params, sizeof(d3params) );

	// Get the default diplay adapter mode
	D3DDISPLAYMODE d3Display;
	direct3DInterface->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3Display);

	if(camera->FullScreen())
	{
		d3params.Windowed = false;
		d3params.BackBufferWidth = camera->Width();
		d3params.BackBufferHeight = camera->Height();
		d3params.BackBufferFormat = D3DFMT_A8R8G8B8;
	}
	else 
	{
		d3params.Windowed = true;
		d3params.BackBufferFormat = d3Display.Format;
	}

	d3params.hDeviceWindow = *window;
	d3params.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3params.EnableAutoDepthStencil = TRUE;
	d3params.AutoDepthStencilFormat = D3DFMT_D24S8;
	//d3params.AutoDepthStencilFormat = D3DFMT_D16;
	d3params.BackBufferCount = 1;
  d3params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

	// Try to create the render device
	if(FAILED(direct3DInterface->CreateDevice(
						D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, *window,
						D3DCREATE_HARDWARE_VERTEXPROCESSING,
						&d3params, &direct3DRenderer)))
	{
		lighting = false;
		if(FAILED(direct3DInterface->CreateDevice(
							D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, *window,
							D3DCREATE_SOFTWARE_VERTEXPROCESSING,
							&d3params, &direct3DRenderer)))
		{
			MessageBox(0, L"Unable to create device.", L"Failure", 0);
			return false;
		}
	}

	// BBox index buffer
	BuildBBoxIndexBuffer();

	return true;
}

bool Engine::InitStates() 
{
	// Turn off culling, so we see the front and back of the triangle
	#ifndef USE_CULLING
	if(FAILED(direct3DRenderer->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE)))
				MessageBox(0, L"Failure", L"SetRenderState", 0);
	#endif

	// Lights
	#ifndef USE_LIGHTS
	if(FAILED(direct3DRenderer->SetRenderState(D3DRS_LIGHTING, FALSE)))
				MessageBox(0, L"Failure", L"SetRenderState", 0);
	#endif

	// Texture States
	#ifdef USE_TEX
	if(FAILED(direct3DRenderer->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE)))
				MessageBox(0, L"Failure", L"SetTextureStageState", 0);
	if(FAILED(direct3DRenderer->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE)))
				MessageBox(0, L"Failure", L"SetTextureStageState", 0);
	if(FAILED(direct3DRenderer->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT)))
				MessageBox(0, L"Failure", L"SetTextureStageState", 0);
	if(FAILED(direct3DRenderer->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR)))
				MessageBox(0, L"Failure", L"SetSamplerState", 0);
	if(FAILED(direct3DRenderer->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR)))
				MessageBox(0, L"Failure", L"SetSamplerState", 0);
	if(FAILED(direct3DRenderer->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP)))
				MessageBox(0, L"Failure", L"SetSamplerState", 0);
	if(FAILED(direct3DRenderer->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP)))
				MessageBox(0, L"Failure", L"SetSamplerState", 0);/**/
	#endif

	// Turn on the zbuffer
	if(FAILED(direct3DRenderer->SetRenderState(D3DRS_ZENABLE, TRUE)))
				MessageBox(0, L"Failure", L"SetRenderState", 0);

	return true;
}

bool Engine::InitFonts() 
{
	// Font stuff
	TCHAR strFont[LF_FACESIZE];
	StringCchCopy( strFont, 32, L"Arial" );

	D3DXCreateFont(direct3DRenderer,      // D3D device
                 14,                    // Height
                 0,                     // Width
                 FW_NORMAL,             // Weight
                 1,                     // MipLevels, 0 = autogen mipmaps
                 FALSE,                 // Italic
                 DEFAULT_CHARSET,       // CharSet
                 OUT_DEFAULT_PRECIS,    // OutputPrecision
                 DEFAULT_QUALITY,       // Quality
                 DEFAULT_PITCH | FF_DONTCARE, // PitchAndFamily
                 strFont,               // pFaceName
                 &fontS);               // ppFont

	D3DXCreateFont(direct3DRenderer,      // D3D device
                 36,                    // Height
                 0,                     // Width
                 FW_NORMAL,             // Weight
                 1,                     // MipLevels, 0 = autogen mipmaps
                 FALSE,                 // Italic
                 DEFAULT_CHARSET,       // CharSet
                 OUT_DEFAULT_PRECIS,    // OutputPrecision
                 DEFAULT_QUALITY,       // Quality
                 DEFAULT_PITCH | FF_DONTCARE, // PitchAndFamily
                 strFont,               // pFaceName
                 &fontL);               // ppFont

	return true;
}

//
// Main Loop
//

void Engine::MainLoop()
{
	// Show the window
	ShowWindow(*window, SW_SHOWDEFAULT);
	UpdateWindow(*window);

	// Enter the message loop
	MSG msg;
	ZeroMemory(&msg, sizeof(msg));
	while(msg.message != WM_QUIT)
	{
		if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			Render();

			#ifdef FORCE_QUIT_AFTER_RENDER
			EXIT
			#endif
		}
	}
}

//
// Render
//

void Engine::Render()
{
	// Check for render device
	if(!direct3DRenderer)
		return;

	// Sets time
	DWORD thisTime = GetTickCount();
	lastFrameLength = (float)(thisTime - lastTime) / 1000.0f;
	lastTime = thisTime;

	// Render correct window
	state->Render();
}

//
// RenderBillboards
//

void Engine::RenderBillboards()
{
	BillboardGeom::RenderBBGeoms(renderFlag);
}

//
// RenderNormals
//

void Engine::RenderNormals() 
{
	if(renderNormals)
	{
		// Size
		unsigned int size = sizeof(Line) * Geometry::normals.size();

		// Create new buffer
		LPDIRECT3DVERTEXBUFFER9 normalsBuffer; 
		engine.direct3DRenderer->CreateVertexBuffer(
				size, 0, D3DFVF_XYZ,
				D3DPOOL_DEFAULT, &normalsBuffer, NULL);

		// Copy over data
		void *data;
		normalsBuffer->Lock(0, size, (void**)&data, 0);
		memcpy(data, &Geometry::normals[0], size);
		normalsBuffer->Unlock();

		direct3DRenderer->SetStreamSource(0, normalsBuffer, 0, sizeof(Real3));
		direct3DRenderer->SetFVF(D3DFVF_XYZ);
		direct3DRenderer->DrawPrimitive(D3DPT_LINELIST, 0, Geometry::normals.size());

		normalsBuffer->Release();
	}
}

ushort boxLines[] =
{
	0, 1,
	1, 2,
	2, 3,
	3, 0,

	4, 5,
	5, 6,
	6, 7,
	7, 4,

	0, 4,
	1, 5,
	2, 6,
	3, 7
};

//
// BuildBBoxIndexBuffer
//

void Engine::BuildBBoxIndexBuffer()
{
	engine.direct3DRenderer->CreateIndexBuffer(
			24 * sizeof(ushort),	0, D3DFMT_INDEX16,
			D3DPOOL_DEFAULT, &boxIndexBuffer, NULL);

	void *data;
	boxIndexBuffer->Lock(0, 24 * sizeof(ushort), (void**)&data, 0);
	memcpy(data, &boxLines[0], 24 * sizeof(ushort));
	boxIndexBuffer->Unlock();
}

//
// RenderBBoxes
//

void Engine::RenderBBoxes() 
{ 
	if(renderBBoxes)
	{
		DrawStringSmall(5, 50, L"Rendering BBoxes");
		// Verts
		//static vector<Real3> verts;
		vector<Real3> verts;
		scene->GetBBoxVerts(verts);

		// Size
		unsigned int size = verts.size();

		if(size != 0)
		{
			// Create new buffer
			LPDIRECT3DVERTEXBUFFER9 bboxBuffer;
			engine.direct3DRenderer->CreateVertexBuffer(
					size * sizeof(Real3), 0, D3DFVF_XYZ,
					D3DPOOL_DEFAULT, &bboxBuffer, NULL);

			// Copy over data
			void *data;
			bboxBuffer->Lock(0, size * sizeof(Real3), (void**)&data, 0);
			memcpy(data, &verts[0], size * sizeof(Real3));
			bboxBuffer->Unlock();

			direct3DRenderer->SetStreamSource(0, bboxBuffer, 0, sizeof(Real3));
			direct3DRenderer->SetFVF(D3DFVF_XYZ);
			engine.direct3DRenderer->SetIndices(boxIndexBuffer);

			for(uint i = 0; i < size; i+=8)
				engine.direct3DRenderer->DrawIndexedPrimitive(
						D3DPT_LINELIST, i, 0, 8, 0, 12);

			bboxBuffer->Release();
		}
	}
}

//
// Begins Rendering
//

void Engine::BeginRender() 
{
	if(!isRendering)
		direct3DRenderer->BeginScene();
	isRendering = true;
}

//
// Ends Rendering
//

void Engine::EndRender() 
{
	if(isRendering)
		direct3DRenderer->EndScene();
	isRendering = false;
}

//
// SwitchBuffers
//

void Engine::SwitchBuffers() 
{
	// Present the backbuffer contents to the display
  direct3DRenderer->Present( NULL, NULL, NULL, NULL );
}

//
// LoadMatrices
//

void Engine::LoadMatrices(D3DXMATRIX *worldMatrix) 
{
	direct3DRenderer->SetTransform(D3DTS_WORLD,      worldMatrix);
	direct3DRenderer->SetTransform(D3DTS_VIEW,       camera->ViewMatrix());
	direct3DRenderer->SetTransform(D3DTS_PROJECTION, camera->ProjMatrix());
}

//
// SetupLights
//

void Engine::SetupLights() 
{
  ZeroMemory(&light, sizeof(D3DLIGHT9));
  light.Type        = D3DLIGHT_DIRECTIONAL;
  //light.Type        = D3DLIGHT_POINT;
  light.Diffuse.r   = 0.8f;
  light.Diffuse.g   = 0.8f;
  light.Diffuse.b   = 0.8f;

	light.Direction = D3DXVECTOR3(0.0f, -1.0f, 0.0f);

	//light.Position = D3DXVECTOR3(0.0f, 400.0f, 250.0f);
	//light.Attenuation0 = 0.00010f;
	//light.Attenuation1 = 0.0025f;
	//light.Attenuation2 = 0.000004f;

  //light.Range       = 100000.0f;
}

//
// LoadLights
//

void Engine::LoadLights() 
{
	if(lighting)
	{
		//D3DXMATRIX matrix;
    //D3DXMatrixIdentity(&matrix);
		//direct3DRenderer->SetTransform(D3DTS_WORLD, &matrix);

		//light.Direction.x = camera->Direction().x;
		//light.Direction.y = camera->Direction().y;
		//light.Direction.z = camera->Direction().z;

		direct3DRenderer->SetLight(0, &light);
		direct3DRenderer->LightEnable(0, TRUE);
		direct3DRenderer->SetRenderState(D3DRS_LIGHTING, TRUE);

		// Finally, turn on some ambient light.
		direct3DRenderer->SetRenderState(D3DRS_AMBIENT, 0x00F0F0F0);
	}
	else direct3DRenderer->SetRenderState(D3DRS_LIGHTING, FALSE);
}

//
// DrawText
//

void Engine::DrawStringSmall(short x, short y, LPCWSTR str, Color c) 
{
	// Set text position
	RECT rect;
	SetRect(&rect, x, y, 0, 0); 

	// Draws the text
	fontS->DrawText(NULL, str, -1, &rect, DT_NOCLIP, c.color);
}

void Engine::DrawStringLarge(short x, short y, LPCWSTR str, Color c) 
{
	// Set text position
	RECT rect;
	SetRect(&rect, x, y, 0, 0); 

	// Draws the text
	fontL->DrawText(NULL, str, -1, &rect, DT_NOCLIP, c.color);
}

//
// DrawStats
//
void Engine::DrawStats() 
{
	TCHAR str[30];

	StringCchPrintf(str, 30, L"Vertices %d", rVertices);
	engine.DrawStringSmall(305, 5, str);

	StringCchPrintf(str, 30, L"Faces %d", rFaces);
	engine.DrawStringSmall(315, 17, str);

	//StringCchPrintf(str, 30, L"<%3.0f %3.0f %3.0f>", 
	//					mouseCoord.x, mouseCoord.y, mouseCoord.z);
	//engine.DrawString(5, 445, str);

	static float totTime = 0.0f;
	static float avTime = 0.0f;
	static ushort count = 0;

	totTime += lastFrameLength;
	++count;
	if(totTime > 0.3f)
	{
		avTime = (float)count / totTime;
		totTime = 0.0f;
		count = 0;
	}

	StringCchPrintf(str, 30, L"FPS: %3.0f", avTime);
	engine.DrawStringSmall(5, 29, str);
	
}

#define Toggle(X) X = !X;

//
// Process Keys
//

void Engine::ProcessKeys()
{
	if(input.KeyPressedOnce(DIK_C)) Toggle(renderWireframe);
	if(input.KeyPressedOnce(DIK_V)) Toggle(renderPoints);
	//if(input.KeyPressedOnce(DIK_N)) Toggle(renderNormals);
	if(input.KeyPressedOnce(DIK_B)) Toggle(renderBBoxes);
	if(input.KeyPressedOnce(DIK_L)) Toggle(lighting);

	if(input.KeyPressedOnce(DIK_RETURN))
	{
		commandActive = true;
		commandLine.clear();
		commandLine.push_back('~');
	}

	if(input.KeyPressedOnce(DIK_SUBTRACT))
	{
		scene->DecreaseSubdivision();
	}
	if(input.KeyPressedOnce(DIK_ADD))
	{
		scene->IncreaseSubdivision();
	}

	if(input.KeyPressedOnce(DIK_ESCAPE))
		PostQuitMessage(0);
}

//
// CollisionTest
//

bool Engine::CollisionTest(Entity *entity)
{
	if(entity->HasOctree())
		for(uint i = 0; i < scene->Children().size(); ++i)
			if(entity->CollisionTest(scene->Children()[i]))
				return true;

	return false;
}

//
// RunScript
//

bool Engine::RunScript(const vector<string> &toks)
{
	if(toks[0] == "clearscene")
		scene->ClearChildren();
	else if(toks[0] == "exit")
		PostQuitMessage(0);
	else if(toks[0] == "savescene")
	{
		// Check for more toks
		if(toks.size() < 2) return false;

		// Output format
		bool binary = false;
		if(toks.size() > 2 && toks[2] == "b")
			binary = true;

		// Output data
		SaveScene(toks[1], binary);
	}
	else if(toks[0] == "savescenetree")
	{
		// Check for more toks
		if(toks.size() < 2) return false;

		// Output format
		bool binary = false;
		if(toks.size() > 2 && toks[2] == "b")
			binary = true;

		// Output data
		SaveSceneTree(toks[1], binary);
	}
	else if(toks[0] == "loadscene")
	{
		// Check for more toks
		if(toks.size() < 2) return false;

		// read data
		LoadScene(toks[1]);
	}
	else if(toks[0] == "loadentity")
	{
		// Check for more toks
		if(toks.size() < 2) return false;

		// Output format
		bool binary = false;
		if(toks.size() > 2 && toks[2] == "b")
			binary = true;

		// Output data
		LoadEntity(toks[1], binary);
	}
	else if(toks[0] == "loadxmesh")
	{
		// Check for more toks
		if(toks.size() < 2) return false;

		ReadXMesh(scene, toks[1].c_str());
	}
	else if(toks[0] == "load3dsmesh")
	{
		// Check for more toks
		if(toks.size() < 2) return false;

		Read3DSMesh(scene, toks[1].c_str());
	}

	return true;
}

//
// CommandWindow
//

void Engine::CommandWindow()
{
	input.GetText(commandLine, 1);

	if(input.KeyPressedOnce(DIK_ESCAPE)) commandActive = false;
	if(input.KeyPressedOnce(DIK_RETURN))
	{
		commandActive = false;

		messages.push_back(Message(commandLine.substr(1, commandLine.size()-1)));

		if(commandLine.size() > 1)
		{
			vector<string> toks;
			Tokenize(commandLine, toks, " ~");

			RunScript(toks);
		}
	}
}

//
// DrawMessages
//

#define MESSAGE_COLOR __red

void Engine::DrawMessages()
{
	if(commandActive)
		DrawStringSmall(3, camera->Height() - 55, ConvertToTChar(commandLine.c_str()), MESSAGE_COLOR);

	uint s = messages.size();
	for(uint i = 0; i < messages.size(); ++i)
	{
		DrawStringSmall(3, camera->Height() - 55 - (s-i)*15, ConvertToTChar(messages[i].text.c_str()), MESSAGE_COLOR);

		messages[i].time -= lastFrameLength;
		if(messages[i].time < 0)
			messages.erase(messages.begin() + i--);
	}
}

//
// SaveScene
//

void Engine::SaveScene(string fileName, bool inBinary)
{
	fileName = "..\\data\\" + fileName;

	FileStream file(false);
	file.Open(fileName, inBinary);
	if(!file.IsOpen()) return;

	// Set binary
	if(inBinary) file.oFile << 'b';

	// Camera data
	camera->Write(file);

	// Model Data
	scene->Write(file);

	file.Close();
}

void Engine::SaveSceneTree(string dirName, bool inBinary)
{
	dirName = "..\\data\\" + dirName;
	ushort i = 0;
	if((i = dirName.find_first_of('.')) != string::npos)
		dirName = dirName.substr(0, i-1);

	//RemoveDirectory(ConvertToTChar(dirName.c_str()));
	CreateDirectory(ConvertToTChar(dirName.c_str()), NULL);
	dirName += "\\";

	string cameraFile = dirName + "camera.te";
	FileStream file(false);
	file.Open(cameraFile, inBinary);
	if(!file.IsOpen()) return;

	// Set binary
	if(inBinary) file.oFile << 'b';

	// Camera data
	camera->Write(file);
	file.Close();

	// Model Data
	scene->WriteTree(dirName, inBinary);
}

//
// Load Scene
//

void Engine::LoadScene(string fileName)
{
	// Open file
	fileName = "..\\data\\" + fileName;
	FileStream file(true);
	file.Open(fileName, true);

	char binary;
	if(file.IsOpen())
	{ file.iFile >> binary; file.Close(); }
	else return;

	// Clears old scene first
	scene->ClearChildren();

	bool b = (binary == 'b');

	// Reopen file
	file.Open(fileName, b);
	if(file.IsOpen())
	{
		if(b) file.iFile >> binary;

		// Load Camera
		camera->Read(file);

		// Reads in the scene
		scene->Read(file);

		file.Close();
	}
}

//
// Load Entity
//

Entity *Engine::LoadEntity(string fileName, bool inBinary)
{
	fileName = "..\\data\\" + fileName;

	// Open file
	FileStream file(true);
	file.Open(fileName, inBinary);
	if(!file.IsOpen()) return 0;

	Entity *e = new Entity(scene);
	e->Read(file);
	e->GenerateBox();

	// Close file
	file.Close();

	// Octree
	e->GenerateBox();
	e->GenerateOctree();

	return e;
}

//
// Load Height Map
//

Entity *Engine::LoadHeightMap(string fileName)
{
	ushort len = fileName.size() - 4;
	fileName = "..\\data\\Height Maps\\" + fileName;

	// Open file
	FileStream file(true);
	file.Open(fileName, true);
	if(!file.IsOpen()) return 0;

	vector<uchar> data;

	while(file.IsGood())
	{
		uchar c;
		file.Read((char*)&c, sizeof(uchar));
		data.push_back(c);
	}

	file.Close();

	uint size = (uint)sqrt((float)(data.size()-1));

	//uchar hMap[size][size];
	//memcpy(*hMap, &data[0], size*size*sizeof(uchar));

	vector< vector<uchar> > hMap(size);
	for(uint i = 0; i < size; ++i)
	{
		hMap[i].resize(size);
		for(uint j = 0; j < size; ++j)
			hMap[i][j] = data[i*size+j+1];
	}

	Entity *e = new Entity(scene, fileName.substr(fileName.find_last_of("\\")+1, len));
	TerrainGeom *geom = e->CreateTerrainGeom(hMap, 6, Med);

	return e;
}

bool Engine::WriteSettings(const char* filename)
{
	ofstream file(filename);
	if (!file) return false;
	
	file << "[General]" << '\n';
	file << "Name=" << player.Name() << '\n';

	file << '\n';
	file << "[Display]" << '\n';
	file << "Fullscreen=" << (camera->FullScreen() ? 1 : 0) << '\n';
	file << "Width=" << camera->Width() << '\n';
	file << "Height=" << camera->Height() << '\n';

	file << '\n';
	file << "[Controls]" << '\n';
	file << "Speed=" << camera->linearSpeed << '\n';

	file << '\n';
	file << "[Audio]" << '\n';

	file << '\n';
	file << "[Other]" << '\n';

	file << endl;
	file.close();

	return true;
}
